using System;
using System.Collections.Generic;
using System.Linq;
using Tycho.Parser.Peg;

namespace Tycho.Grammar {
    public class ChoiceAssociativityRewriter : IChoiceAssociativityRewriter {
        public IEnumerable<IProduction> RewriteForAssciativity (IEnumerable<IProduction> productions, IProduction baseProduction) {
            var lastNonInfixProductions = new List<IProduction> ();
            var currentChoice = new ChoiceProduction ();

            int index = productions.Count ();
            int indexOfLowestPrecedenceInfixOperator = GetIndexOfLowestPrecedenceInfixOperator (productions, baseProduction);

            foreach (var production in productions.Reverse ()) {
                index--;
                var infixInformation = production.InfixInformation;
                if (!infixInformation.IsInfixWith (baseProduction)) {
                    lastNonInfixProductions.Add (production);
                } else {
                    var remaining = CreateChoice (currentChoice, lastNonInfixProductions);
                    infixInformation.First.Production = remaining;
                    lastNonInfixProductions = new List<IProduction> {remaining, production};
                    if (AreInfixOperatorsOfLowerPrecedence (index, indexOfLowestPrecedenceInfixOperator)) {
                        infixInformation.Last.Production = baseProduction;
                    } else {
                        infixInformation.Last.Production = currentChoice = new ChoiceProduction ();
                    }
                }
            }

            return ((IEnumerable<IProduction>) lastNonInfixProductions).Reverse();
        }

        private int GetIndexOfLowestPrecedenceInfixOperator(IEnumerable<IProduction> productions, IProduction baseProduction)
        {
            int index = 0;
            foreach (var production in productions)
            {
                if (production.InfixInformation.IsInfixWith(baseProduction)) {
                    return index;
                } else {
                    index++;
                }
            }
            return index;
        }

        private bool AreInfixOperatorsOfLowerPrecedence(int index, int indexOfLowestPrecedenceInfixOperator)
        {
            return index <= indexOfLowestPrecedenceInfixOperator;
        }

        private static IProduction CreateChoice (ChoiceProduction currentChoice, IEnumerable<IProduction> lastNonInfixProductions) {
            if (lastNonInfixProductions.Count() > 1) {
                currentChoice.Productions = lastNonInfixProductions.Reverse ().ToArray ();
                return currentChoice;
            } else {
                return lastNonInfixProductions.Single ();
            }
        }
    }
}